package collection;

import exception.CollectionEmptyException;

public class SCircularLinkedList <T> extends ACircularLinkedList<SNode<T>, T>{
	
	@Override
	public SNode<T> createNode(T element) 
	{
		return new SNode<T>(element);
	}

	@Override
	protected SNode<T> getNext(SNode<T> someNode) 
	{
		return someNode.getNext();
	}

	@Override
	public SNode<T> getPrev() 
	{
		if (cursor == null)
		{
			return null;
		}
		
		SNode<T> curNode = cursor;
		while(curNode.getNext() != cursor)
		{
			curNode = curNode.getNext();
		}
		
		return curNode;
	}
	
	@Override
	public SNode<T> getNext() 
	{
		if (cursor == null)
		{
			return null;
		}
		else
		{
			return cursor.getNext();
		}
	}
	
	@Override
	public void moveToPrev() 
	{
		SNode<T> prevNode = getPrev();
		if (prevNode == null)
		{
			return ;
		}
		else
		{
			cursor = prevNode;
		}
	}

	@Override
	public void moveToNext() 
	{
		if (cursor == null)
		{
			return ;
		}
		else
		{
			cursor = cursor.getNext();
		}
	}
	
	@Override
	public void addBefore(SNode<T> someNode) 
	{
		SNode<T> prevNode = getPrev();
		if (prevNode == null)
		{
			return ;
		}
		
		prevNode.setNext(someNode);
		someNode.setNext(cursor);
	}

	@Override
	public void addAfter(SNode<T> someNode) 
	{
		if (cursor == null)
		{
			cursor = someNode;
			cursor.setNext(cursor);
		}
		else
		{
			SNode<T> nextNode = cursor.getNext();
			cursor.setNext(someNode);
			someNode.setNext(nextNode);
		}
	}
	
	private SNode<T> getPrev2Node()
	{
		if (cursor == null)
		{
			return null;
		}
		
		SNode<T> curNode = cursor;
		while( curNode.getNext().getNext() != cursor)
		{
			curNode = curNode.getNext();
		}
		
		return curNode;
	}
	
	@Override
	public SNode<T> removeBefore() 
	{
		if (cursor == null)
		{
			throw new CollectionEmptyException("Circular List");
		}
		
		SNode<T> prev2Node = getPrev2Node();
		SNode<T> prevNode = prev2Node.getNext();
		if (prevNode == cursor) // list has only one element
		{
			SNode<T> cursorNode = cursor;
			cursor = null;

			cursorNode.setNext(null);
			return cursorNode;

		}
		else // list has more than one elements
		{
			prev2Node.setNext(cursor);
			
			prevNode.setNext(null);
			return prevNode;
		}
	}
	
	@Override
	public SNode<T> removeAfter() 
	{
		if (cursor == null)
		{
			throw new CollectionEmptyException("Circular List");
		}
		
		SNode<T> nextNode = cursor.getNext();
		
		if (nextNode == cursor) // list has only one element
		{
			SNode<T> cursorNode = cursor;
			cursor = null;
			
			cursorNode.setNext(null);
			return cursorNode;
		}
		else // list has more than one elements
		{
			SNode<T> next2Node = nextNode.getNext();
			cursor.setNext(next2Node);
			
			nextNode.setNext(null);
			return nextNode;
		}
	}

	@Override
	public void removeCursor() 
	{
		moveToNext();
		removeBefore();
	}

}
